package com.koron.tool.frame;

import java.awt.Component;
import java.awt.event.*;
import java.io.*;
import java.nio.file.*;
import java.nio.file.WatchEvent.Kind;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.swing.*;
import javax.swing.tree.*;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.w3c.dom.Document;
import org.xml.sax.SAXException;

import com.koron.common.KVBean;
import com.koron.localdb.LocalMapper;
import com.koron.mybatis.SessionFactory;
import com.koron.tool.Constant;
import com.koron.tool.MainFrame;
import com.koron.tool.frame.bean.*;
import com.koron.util.Util;

/**
 * 显示代码目录，左边为树形，右边为显示面板
 * 
 * @author swan
 *
 */
public class ResourceFrame extends JInternalFrame {
	MainFrame frame;
	JSplitPane split = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT);
	private final JTree tree = new JTree();
	private ResourceBundle resourceBuddle = ResourceBundle.getBundle(MainFrame.RESOURCEBUDDLE, getLocale());

	public ResourceFrame(MainFrame frame) {
		super("数据库设置");
		this.frame = frame;
		setSize(600, 400);
		setMaximizable(true);
		setClosable(true);
		setIconifiable(true);
		setResizable(true);
		setVisible(true);
		init();
	}

	public void init() {
		split = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, new JScrollPane(tree), new JPanel());
		split.setDividerSize(10);
		split.setDividerLocation(200);
		split.setResizeWeight(0.2);
		getContentPane().add(split);
		initTree();
	}

	private void initTree() {
		tree.setCellRenderer(new SwanTreeCellRenderer());
		SessionFactory factory = new SessionFactory();
		LocalMapper mapper = factory.getMapper(LocalMapper.class);
		List<KVBean> list = mapper.listProperties();
		for (KVBean kvBean : list) {
			if (kvBean.getKey().equals(Constant.SRCPATH)) {
				File rootDir = new File(kvBean.getValue());
				if (!rootDir.exists()) {
					rootDir.mkdirs();
				}
				DefaultMutableTreeNode root = new DefaultMutableTreeNode("代码目录");
				root.add(sub(rootDir));
				Path path = rootDir.toPath();
				watch(path, tree, root);
				tree.setModel(new DefaultTreeModel(root));
				tree.addMouseListener(new MouseAdapter() {
					/*
					 * (non-Javadoc)
					 * 
					 * @see
					 * java.awt.event.MouseAdapter#mouseClicked(java.awt.event
					 * .MouseEvent)
					 */
					@Override
					public void mouseClicked(MouseEvent e) {
						super.mouseClicked(e);
						TreePath tp = tree.getClosestPathForLocation(e.getX(), e.getY());
						DefaultMutableTreeNode treeNode = ((DefaultMutableTreeNode) tp.getLastPathComponent());
						Object o = treeNode.getUserObject();
						System.out.println(o);
						if (o instanceof File) {
							File tmp = (File) o;
							if (tmp.getName().endsWith(".xml"))// xml文件，读取头部，看是否mapper
							{
								try {
									Document doc = DocumentBuilderFactory.newInstance().newDocumentBuilder()
											.parse((File) o);
									if (doc.getDocumentElement().getTagName().equals("mapper"))// mybatis配置文件
									{
										String content = Util.fileToString(tmp, Util.getXmlFileEncode(tmp));
										String nameSpace = doc.getDocumentElement().getAttribute("namespace");
										JPopupMenu jmb = new JPopupMenu();
										JMenu menu = new JMenu("添加方法");
										menu.add(new JMenuItem("查询")).addActionListener(
												new TypeAction(tmp, nameSpace, "select"));
										menu.add(new JMenuItem("新增")).addActionListener(
												new TypeAction(tmp, nameSpace, "insert"));
										menu.add(new JMenuItem("修改")).addActionListener(
												new TypeAction(tmp, nameSpace, "update"));
										menu.add(new JMenuItem("删除")).addActionListener(
												new TypeAction(tmp, nameSpace, "delete"));
										jmb.add(menu);
										matchElement("select", content, jmb, tmp, nameSpace);
										matchElement("insert", content, jmb, tmp, nameSpace);
										matchElement("update", content, jmb, tmp, nameSpace);
										matchElement("delete", content, jmb, tmp, nameSpace);
										jmb.show(tree, e.getX(), e.getY());
									}
								} catch (SAXException | IOException | ParserConfigurationException e1) {
									e1.printStackTrace();
								}

							}
						}
					}
				});
			}
		}
		factory.close();
	}

	/**
	 * 往Mapper中增加一个方法
	 * 
	 * @param file
	 * @param nameSpace
	 * @param type
	 */
	private void addMapperBean(File file, String nameSpace, String type) {
		String insertId = JOptionPane.showInputDialog(resourceBuddle.getString("InputNodeName"));
		if (insertId != null) {
			try {
				File javaFile = new File(MainFrame.config.get(Constant.SRCPATH), nameSpace.replace('.', '/') + ".java");
				String str = "<" + type + " id=\"" + insertId + "\">" + "</" + type + ">\r\n";
				// 要把这句加到文件后面
				String encode = Util.getXmlFileEncode(file);
				String fileStr = Util.fileToString(file, encode);
				Matcher m = Pattern.compile("</mapper>").matcher(fileStr);
				if (m.find()) {
					StringBuilder sb = new StringBuilder(fileStr);
					// 找出的update标签里的字符串
					sb.replace(m.start(), m.start(), str);
					PrintWriter pw = new PrintWriter(file, encode);
					pw.print(sb.toString());
					pw.close();
				}
				String java = "public void " + insertId + "();";
				BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(javaFile),
						MainFrame.config.get(Constant.ENCODE)), 1024);
				String tmp = null;
				StringBuilder sb = new StringBuilder();
				while ((tmp = br.readLine()) != null) {
					sb.append(tmp).append("\n");
				}
				if (sb.length() > 0)
					sb.deleteCharAt(sb.length() - 1);
				br.close();
				if (sb.lastIndexOf("}") != -1) {
					int pos = sb.lastIndexOf("\n", sb.lastIndexOf("}"));
					if (pos != -1)
						sb.replace(pos, pos, java + "\n");
					PrintWriter fw = new PrintWriter(javaFile, MainFrame.config.get(Constant.ENCODE));
					fw.write(sb.toString());
					fw.close();
				}
			} catch (IOException e1) {
				e1.printStackTrace();
			}
		}
	}

	private void matchElement(String type, String content, JPopupMenu jmb, File file, String nameSpace) {
		Pattern pattern = Pattern.compile("<" + type + " [^>]*id=\\\"(.*?)\\\"([^>]*)>([\\d\\D]*?)</" + type + ">");
		Matcher m = pattern.matcher(content);
		while (m.find()) {
			jmb.add(new JMenuItem(m.group(1))).addActionListener(
					new MybatisAction(m.group(1), file, m.group(0), type, nameSpace));
		}
	}

	/**
	 * 监听源代码目录
	 * 
	 * @param path
	 */
	private void watch(Path path, final JTree tree, final DefaultMutableTreeNode root) {
		try {
			final WatchService watch = path.getFileSystem().newWatchService();
			path.register(watch, StandardWatchEventKinds.ENTRY_CREATE, StandardWatchEventKinds.ENTRY_DELETE);
			new Thread(new Runnable() {
				@Override
				public void run() {
					try {
						while (true) {
							WatchKey key = watch.take();
							List<WatchEvent<?>> pollEvents = key.pollEvents();
							for (int i = 0; i < pollEvents.size(); i++) {
								WatchEvent<?> event = pollEvents.get(i);
								Path p = (Path) event.context();
								Kind<?> k = event.kind();
								System.out.println(p + "\t" + k);
								if (k == StandardWatchEventKinds.ENTRY_CREATE) {
									DefaultMutableTreeNode node = new DefaultMutableTreeNode(p.toFile());
									((DefaultTreeModel) tree.getModel()).insertNodeInto(root, node, 0);
								} else if (k == StandardWatchEventKinds.ENTRY_DELETE) {

								}
							}
							if (!key.reset())
								break;
						}
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
			}).start();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	/**
	 * 文件夹的树形显示
	 * 
	 * @param f
	 * @return
	 */
	private DefaultMutableTreeNode sub(File f) {
		if (f == null)
			return null;
		if (f.isFile()) {
			return new DefaultMutableTreeNode(f);
		} else if (f.isDirectory()) {
			DefaultMutableTreeNode dir = new DefaultMutableTreeNode(f.getName());
			File[] files = f.listFiles();
			Arrays.sort(files, new Comparator<File>() {
				@Override
				public int compare(File o1, File o2) {
					return (o1.isDirectory() ? 0 : 1) - (o2.isDirectory() ? 0 : 1);
				}
			});
			if (files == null)
				return dir;
			for (File file : files) {

				dir.add(sub(file));
			}
			return dir;
		}
		return null;
	}

	/**
	 * 目录树的显示控制
	 * 
	 * @author swan
	 *
	 */
	class SwanTreeCellRenderer extends DefaultTreeCellRenderer {
		@Override
		public Component getTreeCellRendererComponent(JTree tree, Object value, boolean sel, boolean expanded,
				boolean leaf, int row, boolean hasFocus) {
			super.getTreeCellRendererComponent(tree, value, sel, expanded, leaf, row, hasFocus);
			Object o = value;
			if (value instanceof DefaultMutableTreeNode) {
				DefaultMutableTreeNode o2 = ((DefaultMutableTreeNode) value);
				o = o2.getUserObject();
				if (o instanceof File)
					setText(((File) o).getName());
				else {
					setText(o.toString());
				}
			}
			return this;
		}
	}

	class MybatisAction implements ActionListener {
		String id;
		File file;
		String content;
		String type;
		String nameSpace;

		public MybatisAction(String id, File file, String content, String type, String nameSpace) {
			super();
			this.id = id;
			this.file = file;
			this.content = content;
			this.type = type;
			this.nameSpace = nameSpace;
		}

		@Override
		public void actionPerformed(ActionEvent e) {
			switch (type) {
			case "select":
				split.setRightComponent(new JScrollPane(new SelectPanel(new SelectBean(file, id, content, nameSpace))));
				break;
			case "update":
				split.setRightComponent(new JScrollPane(new UpdatePanel(new UpdateBean(file, id, content, nameSpace))));
				break;
			case "delete":
				split.setRightComponent(new JScrollPane(new DeletePanel(new DeleteBean(file, id, content, nameSpace))));
				break;
			case "insert":
				split.setRightComponent(new JScrollPane(new InsertPanel(new InsertBean(file, id, content, nameSpace))));
				break;
			default:
				break;
			}
		}
	}

	class TypeAction implements ActionListener {
		File file;
		String type;
		String nameSpace;

		public TypeAction(File file, String nameSpace, String type) {
			super();
			this.file = file;
			this.type = type;
			this.nameSpace = nameSpace;
		}

		@Override
		public void actionPerformed(ActionEvent e) {
			addMapperBean(file, nameSpace, type);
		}
	}
}
